﻿using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using System.Windows;

using Client.Common;
using Client.DAL;
using Client.Events;

using Models;

using Newtonsoft.Json;

using Panuon.UI.Silver;

using Prism.Commands;
using Prism.Events;
using Prism.Mvvm;
using Prism.Regions;

namespace Client.ViewModels
{
    public class SaleBillViewModel : BindableBase, IRegionMemberLifetime
    {
        #region 绑定属性

        //有效码列表
        private ObservableCollection<BillEntryModel> _validList;

        public ObservableCollection<BillEntryModel> ValidList
        {
            get { return _validList; }
            set { SetProperty(ref _validList, value, "ValidList"); }
        }

        //选择的有效码
        private object _selectedValid;

        public object SelectedValid
        {
            get { return _selectedValid; }
            set { SetProperty(ref _selectedValid, value, "SelectedValid"); }
        }

        //无效码列表
        private ObservableCollection<BillEntryModel> _invalidList;

        public ObservableCollection<BillEntryModel> InvalidList
        {
            get { return _invalidList; }
            set { SetProperty(ref _invalidList, value, "InvalidList"); }
        }

        //当前选择的客户
        private object _selectedCust;

        public object SelectedCust
        {
            get { return _selectedCust; }
            set { SetProperty(ref _selectedCust, value, "SelectedCust"); }
        }

        //当前客户
        private CustomModel _curCust;

        public CustomModel CurCust
        {
            get { return _curCust; }
            set { SetProperty(ref _curCust, value, "CurCust"); }
        }

        //保存状态
        private Visibility _saveRunning;

        public Visibility SaveRunning
        {
            get { return _saveRunning; }
            set { SetProperty(ref _saveRunning, value, "SaveRunning"); }
        }

        //转圈图标状态
        private bool _saveLoading;

        public bool SaveLoading
        {
            get { return _saveLoading; }
            set { SetProperty(ref _saveLoading, value, "SaveLoading"); }
        }

        #endregion 绑定属性

        #region 属性

        private WindowX _scanWindow;
        private WindowX _selectCustWindow;

        private delegate void ScanCodeEventHandler(string code);

        private readonly IEventAggregator _ea;
        public bool KeepAlive => false;

        #endregion 属性

        #region 命令

        public DelegateCommand AddBillCommand { get; private set; }
        public DelegateCommand NewBillCommand { get; private set; }
        public DelegateCommand RemoveValidCommand { get; private set; }
        public DelegateCommand OpenScanCommand { get; private set; }
        public DelegateCommand SelectCustCommand { get; private set; }

        #endregion 命令

        #region 构造函数

        public SaleBillViewModel(IEventAggregator ea)
        {
            _ea = ea;
            ea.GetEvent<SelCustEvent>().Subscribe(SelectCustEvent);
            ea.GetEvent<ScanCodeEvent>().Subscribe(ScanedCodeEvent);
            SaveRunning = Visibility.Hidden;
            SaveLoading = false;
            ValidList = new ObservableCollection<BillEntryModel>();
            InvalidList = new ObservableCollection<BillEntryModel>();
            AddBillCommand = new DelegateCommand(SaveBill);
            NewBillCommand = new DelegateCommand(NewBill);
            OpenScanCommand = new DelegateCommand(OpenScan);
            SelectCustCommand = new DelegateCommand(OpenSelectCust);
            RemoveValidCommand = new DelegateCommand(RemoveCode);
        }

        #endregion 构造函数

        #region 方法

        #region 打开扫码窗口

        private bool scanning = false;

        private void OpenScan()
        {
            _scanWindow = new Views.ScanCodeView()
            {
                Owner = Comm.Shell,
                Title = "扫码"
            };
            scanning = true;
            Task.Run(RunCode);
            _scanWindow.ShowDialog();
            _scanWindow = null;
            scanning = false;
        }

        #endregion 打开扫码窗口

        #region 打开选择客户窗口

        private void OpenSelectCust()
        {
            _selectCustWindow = new Views.CustSelectView()
            {
                Owner = Comm.Shell
            };
            _selectCustWindow.ShowDialog();
            _selectCustWindow = null;
        }

        #endregion 打开选择客户窗口

        #region 新建单据

        private void NewBill()
        {
            ValidList = new ObservableCollection<BillEntryModel>();
            InvalidList = new ObservableCollection<BillEntryModel>();
            SelectedCust = null;
            CurCust = new CustomModel();
        }

        #endregion 新建单据

        #region 保存单据

        private void CheckSave()
        {
            if (ValidList.Count < 1)
            {
                throw new Exception(" 没有要保存的数据 ");
            }
            if (null == CurCust)
            {
                throw new Exception(" 必须选择客户 ");
            }
            if (CurCust?.Id <= 0)
            {
                throw new Exception(" 必须选择客户 ");
            }
        }

        private StateModel saveState;

        private async void SaveBill()
        {
            SaveRunning = Visibility.Visible;
            SaveLoading = true;
            //处理人ID
            for (int i = 0; i < ValidList.Count; i++)
            {
                ValidList[i].SaleMakerId = Comm.UserInfo.Id;
            }
            try
            {
                CheckSave();
                saveState = new StateModel() { CurStep = Steps.Send };
                BillSrv.AddSaleBill(SaveCallback, CurCust, ValidList.ToList());
                await saveState.CheckState(10);
            }
            catch (Exception ex)
            {
                Comm.ShowErr(ex.Message, "保存单据");
                SaveRunning = Visibility.Hidden;
                SaveLoading = false;
                return;
            }
            if (saveState.CurStep == Steps.Succ)
                NewBill();
            else
                Comm.ShowErr(saveState.ErrStr, "保存单据");
            SaveRunning = Visibility.Hidden;
            SaveLoading = false;
        }

        private void SaveCallback(RetModel rm)
        {
            if (saveState.CurStep != Steps.Send) return;
            saveState.RM = rm;
            saveState.CurStep = rm.Success ? Steps.Succ : Steps.Fail;
        }

        #endregion 保存单据

        #region 扫码处理

        private ConcurrentQueue<string> _codeQueue = new ConcurrentQueue<string>();

        private void ProcessCodeScan(string code)
        {
            if (string.IsNullOrEmpty(code))
                return;
            _codeQueue.Enqueue(code);
        }

        private async void RunCode()
        {
            while (scanning || !_codeQueue.IsEmpty)
            {
                try
                {
                    if (!_codeQueue.TryDequeue(out string code))
                    {
                        System.Threading.Thread.Sleep(100);
                        continue;
                    }

                    BillEntryModel bm;
                    StateModel scanState = new StateModel { CurStep = Steps.Send };
                    void ScanCallback(RetModel rm)
                    {
                        if (scanState.CurStep != Steps.Send) return;
                        scanState.RM = rm;
                        scanState.RM.Data = rm.Success ? rm.Data is null ? null : JsonConvert.DeserializeObject<BillEntryModel>(rm.Data?.ToString()) : null;
                        scanState.CurStep = rm.Success ? Steps.Succ : Steps.Fail;
                    }
                    BillSrv.GetCodeInfo(ScanCallback, code.Replace("\r\n", ""));
                    await scanState.CheckState(10);
                    if (scanState.CurStep == Steps.Succ)
                        bm = CheckErr(code, scanState);
                    else
                        bm = new BillEntryModel { ErrReason = scanState.ErrStr, CodeFull = code };
                    App.Current.Dispatcher.Invoke(() =>
                    {
                        if (bm.ErrReason.IsNullOrEmpty())
                        {
                            bm.SaleMakerId = Comm.UserInfo.Id;
                            ValidList.Add(bm);
                        }
                        else
                        {
                            InvalidList.Add(bm);
                        }
                    });
                }
                catch (Exception)
                {
                }
            }
        }

        private BillEntryModel CheckErr(string code, StateModel scanState)
        {
            BillEntryModel bm;
            if (scanState.RM.Data is BillEntryModel b)
                bm = b;
            else
                bm = new BillEntryModel { ErrReason = "未找到指定编码", CodeFull = code };
            bm.ErrReason = string.IsNullOrEmpty(bm.ErrReason) ?
                bm.CodeStatus != 0 ? "当前编码已经作废" :
                bm.SaleFlag == 1 ? "当前编码已经出库" :
                ValidList.Where(p => p.CodeFull == bm.CodeFull).Any() ? "编码重复扫描" :
                bm.ErrReason :
                bm.ErrReason;
            return bm;
        }

        #endregion 扫码处理

        #region 移除有效码

        private void RemoveCode()
        {
            if (SelectedValid is null)
            {
                Comm.ShowErr("请选择要移除的项目", "移除编码");
                return;
            }
            if (!(SelectedValid is BillEntryModel bem))
            {
                Comm.ShowErr("选择的项目不正确！", "移除编码");
                return;
            }
            ValidList.Remove(bem);
        }

        #endregion 移除有效码

        #region 选择客户事件

        private void SelectCustEvent(CustomModel cm)
        {
            if (null != cm)
                CurCust = cm;
            else
                CurCust = null;
        }

        #endregion 选择客户事件

        #region 扫码事件

        private void ScanedCodeEvent(string code)
        {
            ProcessCodeScan(code);
        }

        #endregion 扫码事件

        #endregion 方法
    }
}